Skip to content

Conversation

@dshulyak
Copy link
Contributor

@dshulyak dshulyak commented Oct 3, 2025

implementation of the #2091

@dshulyak
Copy link
Contributor Author

dshulyak commented Oct 3, 2025

this doesn't include integration code (e.g discovery, dataplane and raptorcast changes) and i still need to add more docs to the code itself

@dshulyak dshulyak force-pushed the dmitry/wireauth branch 3 times, most recently from 070fb7c to 98a6b9b Compare October 8, 2025 12:34
}
}

#[derive(Clone, Debug, Zeroize)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no ZeroizeOnDrop. Is it intentional? It could be useful for tmp_x variables

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i am using Zeroizing for chaining_key and hash output. i think there was no need to zeroize every tmp variable, will recheck

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my reasoning was that those values are always on the stack. so they will be overwritten shortly after function returns.
adding ZeroizeOnDrop overwrites them only a few ns earlier

it likely costs nothing to zeroize them, just feels weird.
boringtun doesn't zeroize intermidiate variables, i am curious how kernel implementation handles those.

.expect("ephemeral private key must be set"),
&msg.ephemeral_public,
)?;
let temp = keyed_hash!(state.chaining_key.as_ref(), ecdh_ee.as_ref());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ephemeral private key of the initiator's state can be erased here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess i can .take() it from the state, but the state itself is dropped (and private key is erased at that point) soon after exiting this function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i kept it as is, dropping it slightly earlier should not make a difference

)
.map_err(CookieError::CookieDecryptionFailed)?;

Ok(reply.encrypted_cookie)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is worth adding a comment that this function decrypts the cookie and returns its value. No comments, and a returned reply.encrypted_cookie is misleading.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will add

Ok((terminated, rekey))
}

pub fn handle_rekey_timer(&mut self) -> RekeyEvent {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is called handle_rekey_timer, but nothing is handled here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, i will refactor this


use crate::error::{ProtocolErrorContext, Result};

pub struct Cookies {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no zeroization for secrets

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think that it accomplishes anything. those secrets can be erased only when authentication protocol is terminated (e.g program closed for example).
and it doesn't matter if they are stolen when protocol is no longer working

pub ip_rate_limit_window: Duration,
pub max_requests_per_ip: usize,
pub ip_history_capacity: usize,
pub psk: [u8; 32],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to add zeroization for Config?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it makes sense to erase psk, as it meant to be long term secret

pub rekey_deadline: Option<Duration>,
pub session_timeout_deadline: Option<Duration>,
pub max_session_duration_deadline: Option<Duration>,
pub stored_cookie: Option<[u8; 16]>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to add zeroization for the cookie secret?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it only allows attacker to bypass dos-filter.
it doesn't cost much to wrap this in Zerozing, but practically it seemed to me unnecessary

use crate::{Initiator, Responder, Transport};
use monad_wireauth_session::{Config, SessionIndex};

pub struct API<C: Context> {
Copy link
Contributor

@dnkolegov-ar dnkolegov-ar Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In WireGuard:

after an initiator receives a handshake response message (section 5.4.3), 
the responder cannot send transport data messages (section 5.4.6)
until it has received the first transport data message from the initiator.
And, further, transport data messages encrypted using the previous secure session might be in transit after a new secure session has been created.
For these reasons, WireGuard keeps in memory the current secure session,
the previous secure session, and the next secure session for the case of an unconfirmed session 

Could you point me to the code where this logic is implemented? Or explain why this is not implemented and why the protocol does not need that functionality.

I think it should be in

fn decrypt_data_packet(&mut self, packet: &mut [u8], remote_addr: SocketAddr) -> Result<bool> {
, but I do not see the entire workflow, only the mechanism that ensures that the initiator must send some data to the responder before the responder starts sending data to the initiator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after an initiator receives a handshake response message (section 5.4.3), 
the responder cannot send transport data messages (section 5.4.6)
until it has received the first transport data message from the initiator.

implemented by having a separate type for Responder, that type can't send messages, but can accept them (decrypt method), and on first successfully decrypted message it transitions to Transport type (establish method)

And, further, transport data messages encrypted using the previous secure session might be in transit after a new secure session has been created.
For these reasons, WireGuard keeps in memory the current secure session,
the previous secure session, and the next secure session for the case of an unconfirmed session 

in api crate (state.rs) i track sessions with different state separately, sessions in Transport state can't be replaced by unconfirmed sessions, once Transport is created there is a call handle_established that evicts older sessions. that covers current secure session (Transport type) and separate unconfirmed session. so initiator or responder will never evict established session until new session transitions to Transport state

there is currently an expectation that both sides will initiate connect before sending messages, and i track 1 of each initiated and accepted instead of previous secure session. it addresses a problem that older session may get evicted during rekey while there are inflight messages

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

though this last part is not very intuitive, i will check how to transition to simply storing 2 last established sessions instead

@dnkolegov-ar
Copy link
Contributor

@dshulyak When can I review the fixes for the findings? I think it makes sense to do one more round of the security review after you fix all current findings/comments.

@dshulyak
Copy link
Contributor Author

@dnkolegov-ar i will push changes by wed 29th

@dshulyak
Copy link
Contributor Author

@dnkolegov-ar i pushed a separate commit with changes for comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants